/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月11日
 */
package com.massyframework.beanskin.runtime.framework.installing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleRepository;
import com.massyframework.beanskin.RequireLibraryDescriptor;
import com.massyframework.beanskin.util.version.VersionRange;

/**
 * 简单的依靠类库交集计算器
 * 
 * @author huangkh
 *
 */
public class SimpleRequireLibraryIntersetor {

	private static Logger LOG = LoggerFactory.getLogger(SimpleRequireLibraryIntersetor.class);
	
	/**
	 * 
	 */
	public SimpleRequireLibraryIntersetor() {
	}

	/**
	 * 取依赖交集
	 * @param identifier {@link ModuleIdentifier} 模块标识符
	 * @param requires {@link List}, {@code identifier}模块所依赖的类库描述集合
	 * @param moduleRepository {@link ModuleRepository},模块工厂
	 * @return {@link RequireLibraryDescriptor}, 最终计算的结果
	 */
	public List<RequireLibraryDescriptor> intersection(ModuleIdentifier identifier, List<RequireLibraryDescriptor> requires,
			ModuleRepository moduleRepository) {
		if (requires == null) return Collections.emptyList();
		
        Map<String, List<RequireLibraryDescriptor>> map = new LinkedHashMap<>();
        this.resolveRequireModules(identifier, requires, moduleRepository,  map);

        List<RequireLibraryDescriptor> result = new ArrayList<RequireLibraryDescriptor>();
        for (Map.Entry<String, List<RequireLibraryDescriptor>> entry: map.entrySet()) {
        	RequireLibraryDescriptor rcl = this.completeIntersection(identifier, entry.getValue());
            if (rcl != null) {
                result.add(rcl);
            }
        }
        return result;
	}

	/**
     * 计算交集
     * @param identifier {@link ModuleIdentifier} 模块标识符
     * @param requires {@link List};
     */
    protected RequireLibraryDescriptor completeIntersection(ModuleIdentifier identifier, List<RequireLibraryDescriptor> requires) {
        int size = requires.size();
        RequireLibraryDescriptor require = requires.get(0);
        if (size == 1) {
            return require;
        }

        VersionRange versionRange = require.getVersionRange();
        for (int i=1; i<size; i++ ) {
            versionRange = versionRange.intersection(requires.get(i).getVersionRange());
        }

        if (versionRange.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            builder.append(identifier.toIdentifier())
                    .append(" require [groupId=")
                    .append(require.getGroupId())
                    .append(", moduleId=")
                    .append(require.getModuleId())
                    .append("] is empty.");
            if (LOG.isErrorEnabled()) {
                LOG.error(builder.toString());
            }
            return null;
        }
        
        RequireLibraryDescriptor.Builder builder =
        		RequireLibraryDescriptor.newBuilder()
	        		.groupId(require.getGroupId())
	        		.moduleId(require.getModuleId())
	        		.versionRange(versionRange)
	        		.transitive(true);
        return builder.build();
    }


    /**
     * 解析要求的插件。
     * <p>
     * 如果依靠的模块支持传递，则需要递归解析可传递模块的依靠模块。
     * @param identifier {@link ModuleIdentifier}
     * @param requires {@link List}, RequireComponentLib列表
     * @param moduleRepository {@link ModuleRepository}, 模块仓储
     * @param resolved {@link List},解析后的依赖模块列表
     */
    protected void resolveRequireModules(ModuleIdentifier identifier, List<RequireLibraryDescriptor> requires,
                                         ModuleRepository moduleRepository, Map<String, List<RequireLibraryDescriptor>> resolved){
        for (RequireLibraryDescriptor require: requires) {
        	List<Module<?>> modules = moduleRepository.getModules((Predicate<Module<?>>) m -> require.isRequire(m));
        	for (Module<?> module: modules) {
        		//依赖模块的依赖，支持透传的需要加入。
        		List<RequireLibraryDescriptor> rcls = module.getConfig().getRequires();
        		for (RequireLibraryDescriptor rcl: rcls) {
        			if (rcl.isTransitive()) {
        				List<RequireLibraryDescriptor> value = 
        						resolved.computeIfAbsent(rcl.getGroupId().concat(":").concat(rcl.getModuleId()),
        								key -> new ArrayList<RequireLibraryDescriptor>());
        				value.add(rcl);
        			}
        		}
        	}
        	
        	if (!modules.isEmpty()) {
        		List<RequireLibraryDescriptor> value =
                        resolved.computeIfAbsent(require.getGroupId().concat(":").concat(require.getModuleId()),
                                name -> new ArrayList<RequireLibraryDescriptor>());
                value.add(require);
        	}
        }
    }
    
}
